// A hack to follow LLVM's build status.
#ifndef NDEBUG
  #define IS_DEBUG
#endif

#include "llvm/CodeGen/OptSched/OptSchedMachineWrapper.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/CodeGen/OptSched/generic/logger.h"
namespace opt_sched {

using namespace llvm;

LLVMMachineModel::LLVMMachineModel(llvm::SelectionDAGISel* IS) {
  const TargetMachine& target = IS->TM;

  mdlName_ = target.getTarget().getName();

  // TODO(max99x): Get real values for pipeline-related vars.
  issueRate_ = 1;
  issueSlotCnt_ = 1;
  IssueTypeInfo issueType;
  issueType.name = "Default";
  issueType.slotsCount = 1;
  issueTypes_.push_back(issueType);

  // TODO(max99x): Get real values for dependency latencies.
  dependenceLatencies_[DEP_DATA] = 1;
  dependenceLatencies_[DEP_ANTI] = 0;
  dependenceLatencies_[DEP_OUTPUT] = 1;
  dependenceLatencies_[DEP_OTHER] = 1;

//Logger::Info("Machine model: %s", mdlName_.c_str());
  // TODO(max99x): Improve register pressure limit estimates.
  const TargetRegisterInfo* regInfo = target.getRegisterInfo();
  for (TargetRegisterClass::sc_iterator cls = regInfo->regclass_begin();
       cls != regInfo->regclass_end();
       cls++) {
    RegTypeInfo regType;
    regType.name = (*cls)->getName();
    regType.count = regInfo->getRegPressureLimit(*cls, *IS->MF);
    // HACK: Special case for the x86 flags register.
    if (mdlName_.find("x86") == 0 && regType.name == "CCR") {
      regType.count = 1;
    }
    if (regType.count > 0) {
      // Only count types with non-zero limits.
      regClassToType_[*cls] = registerTypes_.size();
      regTypeToClass_[registerTypes_.size()] = *cls;
      registerTypes_.push_back(regType);
//Logger::Info("Reg Type %s has a limit of %d",regType.name.c_str(), regType.count);
    }
  }

  // TODO(max99x): Get real instruction types.
  InstTypeInfo instType;

  instType.name = "Default";
  instType.isCntxtDep = false;
  instType.issuType = 0;
  instType.ltncy = 1;
  instType.pipelined = true;
  instType.sprtd = true;
  instType.blksCycle = false;
  instTypes_.push_back(instType);

  instType.name = "artificial";
  instType.isCntxtDep = false;
  instType.issuType = 0;
  instType.ltncy = 1;
  instType.pipelined = true;
  instType.sprtd = true;
  instType.blksCycle = false;
  instTypes_.push_back(instType);
}

int LLVMMachineModel::GetRegType(const llvm::TargetRegisterClass* cls) const {
  // HACK: Map x86 virtual RFP registers to VR128.
  if (mdlName_.find("x86") == 0 && std::string(cls->getName(), 3) == "RFP") {
    return GetRegTypeByName("VR128");
  }
  assert(regClassToType_.find(cls) != regClassToType_.end());
  return regClassToType_.find(cls)->second;
}

const llvm::TargetRegisterClass* LLVMMachineModel::GetRegClass(int type) const {
  assert(regTypeToClass_.find(type) != regTypeToClass_.end());
  return regTypeToClass_.find(type)->second;
}

} // end namespace opt_sched
